home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-04-10 | 61.4 KB | 1,898 lines | [TEXT/MPS ] |
- /*---------------------------------------------------------------------------
- FILENAME
- UniversalMessageIntf.c
-
- DESCRIPTION
- This file contains the routines which override the universal imaging
- messages that the LaserWriter SC utilizes.
-
- COPYRIGHT
- Copyright Apple Computer, Inc. 1989-1992
- All rights reserved.
-
- INTERFACE ROUTINES:
- SD_Initialize
- SD_ShutDown
- SD_DefaultPrinter
- SD_DespoolPage
- SD_SetupImageData
- SD_OpenConnection
- SD_CloseConnection
- SD_StartSendPage
- SD_FinishSendPage
- SD_WriteData
- SD_CheckStatus
- SD_GetDeviceStatus
- SD_CreateImageFile
- SD_RasterDataIn
- SD_ChooserMessage
-
- -------------------------------------------------------------------------------- */
-
- // Include the standard Mac header files
- #include "MacIncludes.h"
-
- // Include the new QuickDraw GX graphics header files
- #include <graphics routines.h>
- #include <graphics libraries.h>
- #include <math routines.h>
- #include <qd library.h>
-
- // Include the required Printing Manager header files
- #include <PrintingManager.h>
- #include <PrintingMessages.h>
- #include <PrintingDrivers.h>
- #include <Collections.h>
- #include <Messages.h>
- #include <PrintingResTypes.h>
- #include <PrintingErrors.h>
-
- #include <GXExceptions.h>
-
- // Include the internal driver constants and types used by this module
- #include "LaserSCResources.h"
- #include "UniversalMessageIntf.h"
- #include "LaserSCIntf.h"
- #include "SCPrinterStatus.h"
-
- /***************************************************************************************
- * INTERNAL ROUTINES *
- ***************************************************************************************/
-
- /****************************************************************************************
-
- IsGXVersionNewEnough
-
- function:
- This routine checks to see if our driver is too new for the
- installed version of QuickDraw GX. We require version 1.1,
- since we rely on the 1.1 gxSetupPageImageData message.
-
- parameters:
- anErr error result (noErr or kSilentError.)
- kSilentError is a positive number. QDGX
- will not alert for print jobs that fail
- with positive error codes.
-
- returns:
- true if version is ok, otherwise false.
-
- ****************************************************************************************/
-
- Boolean IsGXVersionNewEnough(OSErr *anErr)
- {
- long theVersion;
- gxStatusRecord *pStatus;
-
- // We require version 1.1 or later, so make sure we have it.
-
- if ((Gestalt(gestaltGXVersion, &theVersion) == noErr) &&
- (theVersion >= 0x00010100))
- *anErr = noErr;
- else
- {
- // Allocate a status record large enough to handle status with the largest buffer size.
-
- pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + gxDefaultStatusBufferSize);
- *anErr = MemError();
- require(*anErr == noErr, NewPtrClearFailed);
-
- // Initialize the appropriate fields within the status record
-
- pStatus->statusOwner = 'drvr';
- pStatus->statResId = kEngineStatusStatID;
- pStatus->statResIndex = kDriverTooNewIdx;
- pStatus->bufferLen = gxDefaultStatusBufferSize;
-
- // Now display the alert to the user
- do
- {
- // Issue the alert to the user
- *anErr = GXAlertTheUser(pStatus);
- }
- while (pStatus->dialogResult == nil);
-
- // Kill the status pointer
- DisposPtr((Ptr) pStatus);
-
- NewPtrClearFailed:
-
- // Return a positive error code, so GX will not put up another alert,
- // but will put any job in progress on hold.
-
- *anErr = kSilentError;
- }
-
- return ((*anErr == noErr)? true: false);
- }
-
-
- /****************************************************************************************
-
- FixRoundRectangle
-
- function:
- This routine is a utility function which rounds the coordinate values within
- the rectangle passed in.
-
- parameters:
- r rectangle whose coordinates are to be rounded
-
- returns:
- None
-
- ****************************************************************************************/
- void FixRoundRectangle(gxRectangle *r)
- {
- r->top = ff(FixRound(r->top));
- r->left = ff(FixRound(r->left));
- r->bottom = ff(FixRound(r->bottom));
- r->right = ff(FixRound(r->right));
- }
- /* FixRoundRectangle */
-
-
- /****************************************************************************************
-
- AlignPage
-
- function:
- This routine is called to adjust the raster imaging system's page size
- rectangle so that it's zero based and long word aligned.
- It also returns a QuickDraw device rectangle which represents the page
- centered (left to right) in the SC's imaging area. The device rectangle is
- used to set the margins on the printer in SD_StartSendPage.
-
- parameters:
- pageBounds raster imaging system's pageSize rect
- deviceRect rectangle representing the device rectangle for the LWSC
- maxPageHeight maximum height allowed for the pageBounds and deviceRect rectangles
-
- returns:
- None
-
- ****************************************************************************************/
- void AlignPage(gxRectangle *pageBounds, Rect *deviceRect, Fixed maxPageHeight)
- {
- gxRectangle tempBounds;
- Fixed leftMargin;
- Fixed width;
- short leftEdge;
- Fixed paperWidth;
-
- // First force the pageBounds rectangle to be zero based.
-
- pageBounds->right -= pageBounds->left;
- pageBounds->left = ff(0);
- pageBounds->bottom -= pageBounds->top;
- pageBounds->top = ff(0);
-
- // Force the page size rectangle's width to be within the max. range
- if (pageBounds->right > kMaxPageWidth)
- pageBounds->right = kMaxPageWidth;
-
- // Force the page size rectangle's height to be within the max. range
-
- if (pageBounds->bottom > maxPageHeight)
- pageBounds->bottom = maxPageHeight;
-
- // Force the page to be long-aligned because the offscreen code forces long alignment.
- // We do this by long aligning the page width, and then resetting the left and
- // right edges.
-
- width = ( (pageBounds->right + ff(31)) >> (5+16)) << (5+16);
-
- pageBounds->right = width;
- FixRoundRectangle(pageBounds);
-
- // Now we create the deviceRect starting with the adjusted pageSize rectangle
- tempBounds = *pageBounds;
-
- // Center the page (left to right) on the engine. The top margin is always the minimum margin
-
- tempBounds.top += kMinSCTopMargin;
- tempBounds.bottom += kMinSCTopMargin;
-
- paperWidth = pageBounds->right - pageBounds->left;
- leftMargin = (kMaxPaperWidth - paperWidth) >> 1;
- leftEdge = (((leftMargin >> 16) + 7 ) >> 3) << 3; // ( (margin + 7) / 8) * 8
- tempBounds.left = ff(leftEdge);
- tempBounds.right = tempBounds.left + width;
-
- FixRoundRectangle(&tempBounds);
- FixedRectToShort(&tempBounds, deviceRect);
- }
- /* AlignPage */
-
-
- /****************************************************************************************
-
- JobIsBestQuality
-
- function:
- This routine is called to determine if the job the driver is currently
- processing is to be output in best quality or rough quality. The function
- returns true if best quality, and false otherwise.
-
- parameters:
- None
-
- returns:
- Boolean true if best quality job; false otherwise
-
- ****************************************************************************************/
- Boolean JobIsBestQuality(void)
- {
- OSErr anErr;
- Boolean isFinal;
- gxQualityInfo jobQualitySettings;
- long itemSize = sizeof(jobQualitySettings);
-
- // Retrieve the quality setting info from the job
- anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
- check(anErr == noErr);
-
- isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
-
- return(isFinal);
- }
- /* JobIsBestQuality */
-
-
- /****************************************************************************************
-
- SC_HandleManualFeed
-
- function:
- This routine is called at FinishSendPage time when the user needs to be
- prompted to place the correct paper into the printer for a manual feed
- job. This routine calls ResolvePrinterProblem to prompt the user
- and field his responses. If the user decides to abort the print job, then
- this routine will return an error of prUserAbortErr. If the problem
- is resolved successfully, then this routine returns noErr.
-
- parameters:
- thePaperType the Paper Type that should be loaded into the printer
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SC_HandleManualFeed(gxPaperType thePaperType)
- {
- OSErr anErr;
- short dialogResult;
- long printerProblem;
-
- // Set printerProblem to indicate the type of problem encountered
-
- SetPrinterProblemStatResIndex(kOutOfPaperStatIdx, &printerProblem);
- SetPrinterProblemStatResID(kTransmissionStatID, &printerProblem);
-
- // Prompt the user to put paper into the printer. This routine will return anErr of
- // prUserAbortErr if the user aborts the print job.
-
- anErr = ResolvePrinterProblem(printerProblem, isManualFeed, thePaperType, &dialogResult);
- require(anErr == noErr, ResolvePrinterProblem);
-
- switch (dialogResult)
- {
- case nil:
- case ok:
- // User loaded the paper and may or may not have clicked OK by the time we discovered
- // that the printer now has paper.
- break;
-
- case gxAutoFeedButtonId:
- // User wishes to do the remainder of the job using the paper cassette. Update job to
- // relfect auto-feed and tell the printer to feed paper from the cassette.
-
- {
- Collection jobCollection;
- gxPaperFeedInfo paperFeed;
- gxTrayFeedInfo trayFeedInfo;
- long itemSize = sizeof(trayFeedInfo);
-
- jobCollection = GXGetJobCollection( GXGetJob() );
-
- /* Update for job */
- paperFeed.autoFeed = true;
- (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
-
- /* Update as it may be reused */
- anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
- if (anErr == noErr) {
- trayFeedInfo.manualFeedThisPage = false; /* Other trayInfo fields are still valid */
- (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
- }
- }
-
- // Tell printer to switch to paper feed from the cassette
- anErr = LaserSC_SetBuffandFeedMode( !isManualFeed, // T => do manual feed; F => auto-feed
- true); // T => do buffered printing; F => wait for Print command to complete
- require(anErr == noErr, LaserSC_SetBuffandFeedMode);
-
- break;
-
- default:
- check(0);
- break;
- }
-
-
- /******* Clean-up *******/
-
- LaserSC_SetBuffandFeedMode:
- ResolvePrinterProblem:
- return(anErr);
- }
- /* SC_HandleManualFeed */
-
-
- /********************************************************************************************
-
- GenTIBProgram
- function:
- GenTIBProgram creates a generic Transfer Instruction Block program which is used to
- perform all SCSI data transfer operations (refer to SCSI Manager documentation for
- info. on TIB's). It uses the function's parameters to customize the data transfer
- operations of the TIB program.
-
- parameters:
- tibProgram Pointer to the TIB program generated (returned)
- dataBuffer Pointer to buffer to be used for input or output data xfer
- bytesToXfer Total number of bytes to send or receive
- bytesPerChunk Number of bytes to send or receive in each chunk (during TIB transfer)
-
- returns:
- None
-
- ********************************************************************************************/
- void GenTIBProgram(SCSIInstr tibProgram[],
- Ptr dataBuffer,
- long bytesToXfer,
- long bytesPerChunk)
- {
- long numChunks;
- long numRemBytes;
-
- numChunks = bytesToXfer / bytesPerChunk; // Integral number of byte chunks to send
- numRemBytes = bytesToXfer % bytesPerChunk; // Leftover characters to be sent/received
-
- // Program starts here
- tibProgram[0].scOpcode = scLoop; // count -= 1
- tibProgram[0].scParam1 = 60; // if count > 0 then goto A
- tibProgram[0].scParam2 = numChunks + 1;
-
- tibProgram[1].scOpcode = scLoop; // C: count -= 1
- tibProgram[1].scParam1 = 20; // if count > 0 then goto B
- tibProgram[1].scParam2 = numRemBytes + 1;
-
- tibProgram[2].scOpcode = scStop; // Terminate program
- tibProgram[2].scParam1 = 0;
- tibProgram[2].scParam2 = 0;
-
- tibProgram[3].scOpcode = scMove; // B: Place current dataBuffer pointer into next
- tibProgram[3].scParam1 = (unsigned long) &tibProgram[6].scParam1; // instruction
- tibProgram[3].scParam2 = (unsigned long) &tibProgram[4].scParam1;
-
- tibProgram[4].scOpcode = scNoInc; // Perform data xfer to/from dataBuffer for numRemBytes
- tibProgram[4].scParam1 = (unsigned long) dataBuffer; // Address is set by previous scMove instruction
- tibProgram[4].scParam2 = numRemBytes;
-
- tibProgram[5].scOpcode = scStop; // Terminate the program
- tibProgram[5].scParam1 = 0;
- tibProgram[5].scParam2 = 0;
-
- tibProgram[6].scOpcode = scInc; // A: Perform data xfer to/from dataBuffer for bytesPerChunk
- tibProgram[6].scParam1 = (unsigned long) dataBuffer; // dataBuffer += bytesPerChunk
- tibProgram[6].scParam2 = bytesPerChunk;
-
- tibProgram[7].scOpcode = scLoop; // count -= 1;
- tibProgram[7].scParam1 = -10; // if count > 0 then goto A
- tibProgram[7].scParam2 = numChunks;
-
- tibProgram[8].scOpcode = scLoop; // goto C
- tibProgram[8].scParam1 = -70; //
- tibProgram[8].scParam2 = 2;
- }
- /* GenTIBProgram */
-
-
- /********************************************************************************************
-
- WaitForPageToPrint
- function:
- WaitForPageToPrint is called to force the current printer's page buffer to be
- printed. It handles all error conditions and alerts the user as necessary. This
- routine will return when the page has been printed, the user aborted the job, or
- some fatal printer error was encountered. This routine assumes we've already started
- the page printing by an earlier call to LaserSC_PrintPage (performed in the
- SD_FinishSendPage routine).
-
- parameters:
- manualFeed true => paper is being manually fed; false => paper is auto-fed
- thePaperType paper type of the paper that should be in the printer
- returns:
- OSErr
-
- ********************************************************************************************/
- OSErr WaitForPageToPrint( Boolean manualFeed,
- gxPaperType thePaperType)
- {
- OSErr anErr = noErr;
- OSErr idleErr = noErr;
- short deviceStatus;
-
- // Continue looping until the page is printed, the user aborts, or a fatal error occurs
-
- while (true)
- {
- // Now we must wait until the device is no longer busy (page printed OK) or some problem occurred
- do
- {
- // Get the latest status info from the printer
-
- anErr = LaserSC_GetDeviceStatus(&deviceStatus);
- require(anErr == noErr, LaserSC_GetDeviceStatus);
-
- // Let the client app have a chance to run
- if (idleErr == noErr)
- idleErr = GXJobIdle();
- else
- (void) GXJobIdle();
- }
- while (deviceStatus == kBusy);
-
- // no errors? pick up the idling error
- if (anErr == noErr)
- anErr = idleErr;
-
- // If the device is now ready, then the page must have printed without error
- if (deviceStatus == kGoodCondition)
- {
- break;
- }
- else // Device is not ready; see what problem it may have
- {
- long printerProblem;
-
- // Status the printer to determine the problem it's experiencing
-
- anErr = FindPrinterProblem(&printerProblem, nil);
- require(anErr == noErr, FindPrinterProblem);
-
- // If the printer is out of paper and we're doing a manual feed job, then alert
- // the user to put paper into the printer.
-
- if ( (GetStatResIndex(printerProblem) == kOutOfPaperStatIdx) && manualFeed )
- {
- // Tell the user to put in the paper
- anErr = SC_HandleManualFeed(thePaperType);
-
- // If the error returned is prUserAbortErr, then the user has cancelled the print job
- if (anErr != gxPrUserAbortErr)
- {
- gxTrayFeedInfo trayFeedInfo;
- long itemSize = sizeof(trayFeedInfo);
-
- // If no other error has occurred, then we loop around and try to re-print the page
- require(anErr == noErr, SC_HandleManualFeed);
-
- // Check for switch to auto-feed
- anErr = GetCollectionItem(GXGetJobCollection( GXGetJob() ), gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
- require(anErr == noErr, GetCollectionItem);
-
- // Update cached value if it changed
- if (! trayFeedInfo.manualFeedThisPage) {
- manualFeed = false;
-
- /* Can pass paper type reference as this IS device communication time */
- anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
- nrequire(anErr, GXCheckStatus);
-
- /* No need to reset tray from gxTrayFeedInfo.feedTrayIndex as there is only one tray! */
- }
- }
- else // User canceled manual feed dialog => print job has been cancelled
- break;
- }
- else // Printer is experiencing some other problem; prompt user to resolve it
- {
- short dialogResult;
-
- anErr = ResolvePrinterProblem(printerProblem, !isManualFeed, thePaperType, &dialogResult);
- require(anErr == noErr, ResolvePrinterProblem);
- }
-
- // If we get here, the printer problem has been corrected so we need to re-issue the
- // print command.
-
- anErr = LaserSC_PrintPage( false, // T => print at 8 page per minute rate; F => print normal rate
- false); // T => clear printer's page buffer while printing; F => don't clear buffer
- require(anErr == noErr, LaserSC_PrintPage);
- }
- } // while
-
-
- /******* Clean-up *******/
-
- LaserSC_PrintPage:
- ResolvePrinterProblem:
- GXCheckStatus:
- GetCollectionItem:
- SC_HandleManualFeed:
- FindPrinterProblem:
- JobIdleFails:
- LaserSC_GetDeviceStatus:
- return(anErr);
- }
- /* WaitForPageToPrint */
-
-
- /***************************************************************************************
- * INTERFACE ROUTINES *
- ***************************************************************************************/
-
- /****************************************************************************************
-
- SD_Initialize
-
- function:
- This routine is called when a new job is created to perform some job-oriented
- task, such as conducting dialogs, spooling, and imaging. It allocates the
- driver's globals handle and initializes it.
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_Initialize(void)
- {
- OSErr anErr;
- SpecGlobalsHdl hGlobals;
-
- // Allocate the driver's global handle
-
- hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
- anErr = MemError();
- require(anErr == noErr, NewHandleClear);
-
- // Tell the Printing Manager to save our globals handle for us
- SetMessageHandlerInstanceContext(hGlobals);
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- NewHandleClear:
- return(anErr);
- }
- /* SD_Initialize */
-
-
- /****************************************************************************************
-
- SD_ShutDown
-
- function:
- This routine is called when a job-oriented task has completed and the
- message chain is being destroyed. This routine disposes of the driver's
- globals handle..
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_ShutDown(void)
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Dump the driver's globals handle if it was allocated
-
- if (hGlobals != nil)
- DisposHandle((Handle) hGlobals);
-
- // Make sure the Printing Manager no longer has a reference to our globals handle
- SetMessageHandlerInstanceContext(nil);
-
- return(noErr);
- }
- /* SD_ShutDown */
-
-
- /****************************************************************************************
-
- SD_DefaultPrinter
-
- function:
- This routine is called when a new printer object is being created as a
- result of someone having called NewJob. This message gives the driver the
- opportunity to add any information we want to the new printer object. In
- this case, we add a new viewDevice to the printer object which will allow
- the client application to format a document for this specific device.
-
- parameters:
- thePrinter the newly allocated printer object
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_DefaultPrinter(gxPrinter thePrinter)
- {
- OSErr anErr;
- gxViewDevice vd;
- gxMapping vdMapping;
- gxShape theBitmap;
- gxColorSet theColorSet;
-
- // First we let others in the chain default the printer object before we do.
-
- anErr = Forward_GXDefaultPrinter(thePrinter);
- require(anErr == noErr, Forward_GXDefaultPrinter);
-
- // Create the new viewDevice using a fake bitmap
- {
- gxBitmap aBitmap;
-
- aBitmap.pixelSize = 1;
- aBitmap.rowBytes = 0;
- aBitmap.width = 0;
- aBitmap.height = 0;
- aBitmap.image = (char*)gxMissingImagePointer;
- aBitmap.space = gxNoSpace;
- aBitmap.set = nil;
- aBitmap.profile = nil;
-
- theBitmap = GXNewBitmap(&aBitmap, nil);
- require_action( GXGetGraphicsError(nil) == noErr, NewBitmap, anErr = GXGetGraphicsError(nil); );
-
- vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
- require_action( GXGetGraphicsError(nil) == noErr, NewViewDevice, anErr = GXGetGraphicsError(nil); );
- }
-
- // Now set the view device's color space to be a 1-bit deep indexed space, with two entries (black and white)
- {
- gxSetColor theColors[2];
- gxSetColor *pColor;
-
- pColor = &theColors[0];
-
- // Assign the black and white rgb colors to the indexed color set
-
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF; // white
- pColor++;
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000; // black
-
- theColorSet = GXNewColorSet(gxRGBSpace, 2, theColors);
- require_action( GXGetGraphicsError(nil) == noErr, NewColorSet, anErr = GXGetGraphicsError(nil); );
-
- SetViewDeviceColorSet(vd, theColorSet);
- require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
- }
-
- // Change the viewDevice mapping to include the scaling factor from 72dpi (screen) to 300 dpi (device).
- {
- Fixed xScale;
- Fixed yScale;
-
- xScale = FixRatio(kHorizHighRes, 72);
- yScale = FixRatio(kVertHighRes, 72);
-
- ResetMapping(&vdMapping);
- ScaleMapping(&vdMapping, xScale, yScale, ff(0), ff(0));
-
- GXSetViewDeviceMapping(vd, &vdMapping);
- }
-
- // Add the newly created viewDevice to the printer object
-
- anErr = GXAddPrinterViewDevice(thePrinter, vd);
- require_action( GXGetGraphicsError(nil) == noErr, AddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
-
- // Dispose of the temporary shapes we created along the way
-
- GXDisposeShape(theBitmap);
- GXDisposeColorSet(theColorSet);
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- AddPrinterViewDevice:
- GXDisposeViewDevice(vd);
-
- SetViewDeviceColorSet:
- GXDisposeColorSet(theColorSet);
-
- NewColorSet:
- NewViewDevice:
- GXDisposeShape(theBitmap);
-
- NewBitmap:
- Forward_GXDefaultPrinter:
- return(anErr);
- }
- /* SD_DefaultPrinter */
-
-
- /****************************************************************************************
-
- SD_SetupPageImageData
-
- function:
- This routine is called by the Printing Manager before starting imaging the next
- page to be imaged. We intercept this message to adjust the raster imaging
- system's pageSize rectangle so that it's zero based and long aligned. We
- Also compute the LaserWriter SC's device rectangle so we can use it to set
- the SC's margins in SD_StartSendPage.
-
- parameters:
- theFormat format of the despooled page
- hImageData imaging info for the page
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_SetupPageImageData (gxFormat theFormat, gxShape thePage, gxRasterImageDataHdl hImageData)
- {
- OSErr anErr;
- Rect deviceRect;
- gxRectangle pageSize;
- gxRectangle paperSize;
- gxJob theJob = GXGetJob();
- Fixed maxPageHeight;
-
- // Let the Printing Manager setup the page successfully before we continue
-
- anErr = Forward_GXSetupPageImageData(theFormat, thePage, hImageData);
- require(anErr == noErr, Forward_GXSetupPageImageData);
-
-
- // Fetch the paper type for paper that's supposed to be in the printer. We use its
- // dimensions to restrict the size of the image's page
- // (This is the original format's paper type if unconfigured with a single doc paper type)
-
- GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
-
- // Scale the paperSize to the resolution of the device
- {
- Fixed xScale;
- Fixed yScale;
- gxMapping theMapping;
-
- xScale = FixRatio(kHorizHighRes, 72);
- yScale = FixRatio(kVertHighRes, 72);
-
- ResetMapping(&theMapping);
- ScaleMapping(&theMapping, xScale, yScale, ff(0), ff(0));
-
- MapPoints(&theMapping, 2, (gxPoint *) &paperSize);
- }
-
- // With the paper size scaled to the device resolution, we can now determine the max. page
- // size to allow for this page
- {
- Fixed paperHeight = paperSize.bottom - paperSize.top;
-
- maxPageHeight = paperHeight;
- if (paperHeight <= kMaxLetterPageHeight)
- maxPageHeight = kMaxLetterPageHeight;
- if (paperHeight >= kMaxLegalPageHeight)
- maxPageHeight = kMaxLegalPageHeight;
- }
-
- // We adjust the pageSize rectangle so it's zero based and long word aligned.
- // We also align the device rect to be in line with what we expect for the LWSC,
- // convert it to old QuickDraw coordinates and store it into the globals for
- // use by SD_StartSendPage.
-
- pageSize = (*hImageData)->pageSize;
-
- AlignPage(&pageSize, &deviceRect, maxPageHeight);
-
- (*hImageData)->pageSize = pageSize;
-
- anErr = AddCollectionItem(GXGetFormatCollection(theFormat), 'RECT', 0, sizeof(Rect), &deviceRect);
- nrequire(anErr, AddCollectionItemFails);
-
-
- /******* Clean-up *******/
-
- AddCollectionItemFails:
- Forward_GXSetupPageImageData:
- return(anErr);
- }
- /* SD_SetupPageImageData */
-
-
- /****************************************************************************************
-
- SD_SetupImageData
-
- function:
- This routine is called when the Printing Manager wants us to initialize any
- imaging data that is specific to our type of printer. In our case, we use
- just the default imaging information so all we do is retain the handle for
- later use.
-
- parameters:
- hImageData Handle to the raster imaging data
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
- {
- OSErr anErr;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- check (hGlobals);
-
- // Retain the raster image data handle for later use
- (*hGlobals)->hImageData = hImageData;
-
- // Let others in the message chain do their SetupImageData function
- anErr = Forward_GXSetupImageData(hImageData);
-
- check(anErr == noErr);
- return(anErr);
- }
- /* SD_SetupImageData */
-
-
- /****************************************************************************************
-
- SD_OpenConnection
-
- function:
- This routine is called when the Printing Manager sends the OpenConnection
- message. We take this opportunity to locate a LaserWriter SC printer on
- the SCSI bus, and to make sure it's operational (i.e. no engine or memory
- failure).
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_OpenConnection(void)
- {
- OSErr anErr;
- SCSenseData senseData;
- gxStatusRecord *pStatus;
-
- // Make sure that we're running on GX 1.1 or later.
- // We require the gxSetupPageImageData message which was
- // introduced with 1.1. Normally, GX would check our
- // driver version number and realize that we're too new to
- // run on 1.0.1 or 1.0.2 systems. Unfortunately, versions
- // of QuickDraw GX prior to 1.1 did not check the minor
- // revision of the version number (meaning driver versions
- // 1.0.0 through 1.9.9 would be abole to run on 1.0.1 and 1.0.2.
- // We can't have that, so we do a check ourselves.
-
- if (!IsGXVersionNewEnough(&anErr))
- return anErr;
-
- // Tell user we're attempting to open a connection to the printer
- anErr = GXReportStatus(kTransmissionStatID, kOpeningConnectionStatIdx);
- require(anErr == noErr, ReportStatus);
-
- // Try to locate the LaserWriter SC on the SCSI bus and make sure it's operational.
- // Keep trying to locate the printer until the user aborts (if it can't be found).
-
- anErr = LaserSC_OpenConnection();
- if (anErr == gxAioCantFindDevice) // T => Can't locate device; tell user to turn it on
- {
- // Now we set-up to alert the user that the printer cannot be found
- // Allocate a status record large enough to handle status with the largest buffer size.
-
- pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + gxDefaultStatusBufferSize);
- anErr = MemError();
- require(anErr == noErr, NewPtrClear);
-
- // Initialize the appropriate fields within the status record
-
- pStatus->statusOwner = 'drvr';
- pStatus->statResId = kTransmissionStatID;
- pStatus->statResIndex = kCantFindPrinterStatIdx;
- pStatus->bufferLen = gxDefaultStatusBufferSize;
-
- // Now display the alert to the user
- do
- {
- // Issue the alert to the user
- anErr = GXAlertTheUser(pStatus);
- if (anErr == noErr)
- {
- // Try looking for the device again
- anErr = LaserSC_OpenConnection();
- }
- }
- while ( (anErr == gxAioCantFindDevice) && (pStatus->dialogResult == nil) );
-
- // If the user dismissed the dialog, we are to abort the job
- if (pStatus->dialogResult != nil)
- anErr = gxPrUserAbortErr;
-
- // Always tell the Printing Finder Extension to dismiss the alert
- {
- pStatus->statusOwner = 'univ';
- pStatus->statResId = gxUnivAlertStatusResourceId;
- pStatus->statResIndex = gxUnivPrinterReadyIndex;
-
- // Tell the PFE to remove the alert
- GXAlertTheUser(pStatus);
- }
-
- // Kill the status pointer
- DisposPtr((Ptr) pStatus);
- }
-
- // Forward the message to get standard alerts
- if (anErr == noErr)
- anErr = Forward_GXOpenConnection();
-
- // If any error occurs at this point, then we must abort the open connection
- require(anErr == noErr, LaserSC_OpenConnection);
-
- // In case the printer has just been turned on or reset, issue a request sense
- // command to clear the unit attention status.
- anErr = LaserSC_GetSenseData(&senseData);
-
- check(anErr == noErr);
-
- /******* Clean-up *******/
-
- LaserSC_OpenConnection:
- NewPtrClear:
- ReportStatus:
- return(anErr);
- }
- /* SD_OpenConnection */
-
-
- /****************************************************************************************
-
- SD_CloseConnection
-
- function:
- This routine is called when the Printing Manager issues the CloseConnection
- message. We take this opportunity make sure that if we started printing a
- page at FinishSendPage time, that we force the page to be printed now, or
- the job aborted. We also place the printer into auto-feed mode
- in case it was in manual feed mode. This ensures the printer won't complain
- about there not being any paper in the manual feed slot if we print again soon.
- Other than this, there is nothing else we need to do in order to "sever" a
- connection to an SC printer.
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_CloseConnection (void)
- {
- OSErr anErr;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // At this point in time we must make sure that if we previously printed a non-manual feed
- // page, the page printed successfully. Here we force the page to be printed successfully,
- // unless the user aborts the job or we encounter a fatal printer problem.
-
- if ( (*hGlobals)->printedAPage )
- {
- gxPaperType thePaperType;
-
- thePaperType = GXGetFormatPaperType((*hGlobals)->lastPageFormat);
-
- // Wait for the page to print
-
- anErr = WaitForPageToPrint(!isManualFeed, thePaperType);
-
- // Dispose of the cloned format and update the driver's globals
-
- (*hGlobals)->printedAPage = false;
- GXDisposeFormat((*hGlobals)->lastPageFormat);
-
- require(anErr == noErr, WaitForPageToPrint);
- }
-
- // Set printer to auto feed and non-buffered mode
-
- anErr = LaserSC_SetBuffandFeedMode(false, false);
- check(anErr == noErr);
-
- // Forward the message to get standard alerts, but we don't really care about the result
- (void) Forward_GXCloseConnection();
-
-
- /******* Clean-up *******/
-
- WaitForPageToPrint:
- return(anErr);
- }
- /* SD_CloseConnection */
-
-
- /****************************************************************************************
-
- SD_StartSendPage
-
- function:
- This routine is called by the Printing Manager to signal the start of sending
- a new page to the printer. We first make sure that if we printed a previous
- page, the page printed successfully. Next we query the device to make sure that it's
- ready to accept the next page. If there's a problem, we alert the user so he
- can resolve it. Finally, we set the page margins and dimensions in the printer,
- and clear out the old frame buffer so there's no left over data.
-
- parameters:
- pageFormat format for the page to print
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_StartSendPage (gxFormat pageFormat)
- {
- OSErr anErr;
- short leftMargin; // top left corner of the page
- short topMargin;
- short bytesPerScanline; // rowBytes and height of the page
- short numScanlines;
- Rect actualPage; // unrotated page
- short deviceStatus;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Remember the pageFormat so we can access the manual feed setting at FinishSendPage,
- // which is the time we actually tell the printer to print the page.
-
- (*hGlobals)->pageFormat = pageFormat;
-
- // At this point in time we must make sure that if we previously printed a non-manual feed
- // page, the page printed successfully. Here we force the page to be printed successfully,
- // unless the user aborts the job or we encounter a fatal printer problem.
-
- if ( (*hGlobals)->printedAPage )
- {
- gxPaperType thePaperType;
-
- thePaperType = GXGetFormatPaperType((*hGlobals)->lastPageFormat);
-
- // Wait for the page to print
-
- anErr = WaitForPageToPrint(!isManualFeed, thePaperType);
-
- // Dispose of the cloned format and update the driver's globals
-
- (*hGlobals)->printedAPage = false;
- GXDisposeFormat((*hGlobals)->lastPageFormat);
-
- require(anErr == noErr, WaitForPageToPrint);
- }
-
- // Check to see if the device is ready to accept the next page of data
-
- anErr = LaserSC_GetDeviceStatus(&deviceStatus);
- require(anErr == noErr, LaserSC_GetDeviceStatus);
-
- // Is the device not ready for more data?
- if (deviceStatus != kGoodCondition)
- {
- long printerProblem;
- short dialogResult;
- gxPaperType thePaperType;
- gxTrayFeedInfo trayFeedInfo;
- long itemSize = sizeof(trayFeedInfo);
-
- // Determine if this is a manual feed job
-
- thePaperType = GXGetFormatPaperType(pageFormat);
-
- anErr = GetCollectionItem(GXGetJobCollection( GXGetJob() ), gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
- nrequire(anErr, GetCollectionItem);
-
- // Query the printer to determine its state
-
- anErr = FindPrinterProblem(&printerProblem, nil);
- require(anErr == noErr, FindPrinterProblem);
-
- // If the printer is out of paper and we're doing a manual feed job, then don't
- // alert the user now. Wait until we actually try to print a page (it gives him more
- // time to put the paper in - refer to SD_FinishSendPage).
-
- if ( (GetStatResIndex(printerProblem) != kOutOfPaperStatIdx) || !trayFeedInfo.manualFeedThisPage )
- {
- // Based upon the state of the printer, inform/alert the user to the problem
- // so he can correct it.
-
- anErr = ResolvePrinterProblem(printerProblem, !isManualFeed, thePaperType, &dialogResult);
- require(anErr == noErr, ResolvePrinterProblem);
- }
- }
-
- // If we get here, the printer must be ready for data. Tell user we're preparing the data.
-
- anErr = GXReportStatus(kTransmissionStatID, kPreparingPartOfPageStatIdx);
- require(anErr == noErr, ReportStatus);
-
- // Now we need to set the printer's page margins, as well as the page dimensions.
- // We compute the needed values from the deviceRect we initialized at despool page
- // time. Recall that the deviceRect represents the imaging rectangle within the
- // printers RAM.
-
- GetCollectionItem(GXGetFormatCollection(pageFormat), 'RECT', 0, nil, &actualPage);
- leftMargin = actualPage.left >> 3; // left margin is specified in number of bytes
- topMargin = actualPage.top; // top margin is specified in number of scan lines
- bytesPerScanline = (actualPage.right - actualPage.left) >> 3; // bytesPerScanline is the number of bytes in a single scan line
- numScanlines = actualPage.bottom - actualPage.top; // numScanlines is just the line height of the device rectangle
-
- // Force the margins to be at least as large as the minimum supported by the SC printer
-
- if (topMargin < kMinSCTopMargin)
- topMargin = kMinSCTopMargin;
-
- if (leftMargin < kMinSCLeftMargin)
- leftMargin = kMinSCLeftMargin;
-
- // Set the top and left margin for the printer
-
- anErr = LaserSC_SetPageMargins(leftMargin, topMargin);
- require(anErr == noErr, LaserSC_SetPageMargins);
-
- // Set the page dimensions for the printer
-
- anErr = LaserSC_SetPageDimensions(bytesPerScanline, numScanlines);
- require(anErr == noErr, LaserSC_SetPageDimensions);
-
- // Make sure the printers page frame buffer is cleared out. We offset the
- // actualPage rectangle because the printer assumes the top left corner of the
- // imaging area rectangle is (0, 0).
-
- OffsetRect(&actualPage, -actualPage.left, -actualPage.top);
- anErr = LaserSC_ClearBits(&actualPage);
-
- check(anErr == noErr);
-
-
- /******* Cleanup *******/
-
- LaserSC_SetPageDimensions:
- LaserSC_SetPageMargins:
- ReportStatus:
- ResolvePrinterProblem:
- FindPrinterProblem:
- GetCollectionItem:
- LaserSC_GetDeviceStatus:
- WaitForPageToPrint:
- return(anErr);
- }
- /* SD_StartSendPage */
-
-
- /****************************************************************************************
-
- SD_FinishSendPage
-
- function:
- This routine is called by the Printing Manager to signal that we're at the
- end of the current page. If we're not processing a manual feed job, then we
- simply print the page that's in the printers RAM and alert the user to any
- errors that result. If it's a manual feed job, then we first prompt the user
- to put paper in the printer if there isn't any paper in there currently. For
- auto-feed jobs, we start printing now, but don't wait for it to complete
- until the next StartSendPage or CloseConnection message is issued.
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_FinishSendPage (void)
- {
- OSErr anErr;
- gxPaperType thePaperType;
- gxTrayFeedInfo trayFeedInfo;
- long itemSize = sizeof(trayFeedInfo);
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Determine if this is a manual feed job
-
- thePaperType = GXGetFormatPaperType((*hGlobals)->pageFormat);
-
- anErr = GetCollectionItem(GXGetJobCollection( GXGetJob() ), gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
- nrequire(anErr, GetCollectionItem);
-
- // Set the manual feed mode of the printer based upon the paper configuration, and set the
- // printer's buffered mode so that the SC Print and Clear Bits commands return immediately
- // without waiting for the commands to complete.
-
- anErr = LaserSC_SetBuffandFeedMode(trayFeedInfo.manualFeedThisPage, true);
- require(anErr == noErr, LaserSC_SetBuffandFeedMode);
-
- // Indicate that we are now printing a page
-
- anErr = GXReportStatus(kTransmissionStatID, kPrintingPageStatIdx);
- require(anErr == noErr, ReportStatus);
-
- // Now we issue the Print command to start printing the buffered page. If we're not printing a
- // manual feed job, then we just continue on and will check to make sure the page
- // completed printing at the next StartSendPage message or the next CloseConnection message.
- // If we're printing a manual feed job and there isn't any paper in the printer, then the printer
- // will return an "end-of-media" error and we will alert the user to put paper in
- // the printer. We continue looping, re-issuing the Print command as needed until
- // the page is either printed, or the user aborts the job.
-
- // Issue the print command to start the page printing
-
- anErr = LaserSC_PrintPage( false, // T => print at 8 page per minute rate; F => print normal rate
- false); // T => clear printer's page buffer while printing; F => don't clear buffer
- require(anErr == noErr, LaserSC_PrintPage);
-
- // If this is a manual feed job, wait for the page to print since we need to tell the user to put paper in the printer.
- if (trayFeedInfo.manualFeedThisPage)
- {
- anErr = WaitForPageToPrint(trayFeedInfo.manualFeedThisPage, thePaperType);
- check(anErr == noErr);
-
- (*hGlobals)->printedAPage = false; // No need to check on the printed page later
- }
- else // T => Remember that we've started printing a page so we can check on it later
- {
- gxFormat theFormat;
-
- (*hGlobals)->printedAPage = true;
-
- // Clone the format so we can reference it again at the next StartSendPage or CloseConnection time. The
- // driver disposes of the clone at that time.
-
- theFormat = GXCloneFormat((*hGlobals)->pageFormat);
- (*hGlobals)->lastPageFormat = theFormat;
- }
-
-
- /******* Cleanup *******/
-
- LaserSC_PrintPage:
- ReportStatus:
- LaserSC_SetBuffandFeedMode:
- GetCollectionItem:
- return(anErr);
- }
- /* SD_FinishSendPage */
-
-
- /****************************************************************************************
-
- SD_WriteData
-
- function:
- This routine is called by the Printing Manager to send data to the device.
- This driver uses the routine to complete, or save in globals temporarily,
- the next SCSI command to be issued to the device. It determines whether to
- do the command now or save it for later (to be done in SD_CheckStatus or
- SD_GetDeviceStatus) by examining which SCSI command is to be executed.
-
- If the pData parameter is non-nil, then the routine assumes pData references
- a SCSI command to be issued to the device, and the length parameter specifies
- the size of the command. If the SCSI command does not require additional
- data to be sent/received from the device, then this routine calls the SCSI Manager
- routines SCSIGet, SCSISelect, and SCSICmd in order to complete the SCSI command
- during this call. If the SCSI command requires an additional data transfer,
- then the SCSI command is saved in the driver's globals, and will be issued
- on a subsequent call to SD_CheckStatus or SD_GetDeviceStatus (when the other
- portion of the data transfer is performed) and the command can be completed.
-
- parameters:
- pData pointer to SCSI command to perform
- length size of the SCSI command (bytes)
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_WriteData(Ptr pData, long length)
- {
- OSErr anErr = noErr;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Are we to issue a new SCSI command to the device?
- if (pData != nil)
- {
- short scsiStatus;
- short message;
-
- // Remember what timeout value to use for this printer command when we complete the op.
- (*hGlobals)->timeoutForSCSIComplete = LaserSC_GetTimeoutForSCSICmnd(*((short *) pData));
-
- // If this SCSI command is one we can complete now (i.e. no other data transfer is
- // required), then we do it now. Otherwise, we save the command in the driver's
- // globals and it will be executed on a subsequent call to SD_CheckStatus or
- // SD_GetDeviceStatus.
-
- switch ( *((short *) pData) )
- {
- case kSCPrinterReady: // These SC commands consist only of SCSI commands; do them now
- case kSCResetPrinter:
- case kSCPrint:
-
- // Get control of the SCSI bus before issuing the command
- anErr = SCSIGet();
- require(anErr == noErr, SCSIGetFails);
-
- // Select the target device on the SCSI bus
- anErr = SCSISelect((*hGlobals)->deviceNum);
- require(anErr == noErr, SCSISelectFails);
-
- // Now send the command to the device
- SCSICmd(pData, length);
-
- // Now force completion of the SCSI command
- anErr = SCSIComplete(&scsiStatus, &message, (*hGlobals)->timeoutForSCSIComplete);
- require(anErr == noErr, SCSICompleteFails);
-
- // Remember the last SCSI status in the globals
- (*hGlobals)->lastSCSIStatus = scsiStatus;
-
- break;
-
- default: // All other SC commands require some data transfer with the SCSI command
-
- // Save the SCSI command in the driver's globals for later use
- BlockMove(pData, (Ptr) (*hGlobals)->scsiCommand, length);
-
- // If we're starting a DrawBits command, make sure the appropriate globals are initialized
- if ( *((short *) pData) == kSCDrawBits )
- (*hGlobals)->haveDrawBitsParams = false;
- }
-
- }
-
-
- /******* Clean-up *******/
-
- SCSISelectFails:
- SCSIGetFails:
- SCSICompleteFails:
- return(anErr);
- }
- /* SD_WriteData */
-
-
- /****************************************************************************************
-
- SD_CheckStatus
-
- function:
- This routine is called by the Printing Manager to mark places in which to check
- the status of the device. This driver does not use this routine to retrieve
- the status of the device. Rather, it uses the routine to send data to the
- device.
-
- The pData parameter points to the data to be sent, and the length parameter
- specifies how many bytes to transfer. The statusType parameter specifies
- the number of bytes to transfer in each SCSI data burst, and whether we should
- use the SCSIWrite or SCSIWBlind routines to accomplish the data transfer. If
- statusType is positive, then we should use SCSIWrite; otherwise we use should
- SCSIWBlind. The absolute value of statusType specifies the number of bytes to
- transfer in each SCSI data burst.
-
- When this routine is called for any SCSI command other than DrawBits, the command
- is completed during this call. If the call is for the SC DrawBits command, then
- we only complete the command if the routine is being called to with the bitmap
- data to be sent to the device (when the global variable haveDrawBitsParams is
- true).
-
- parameters:
- pData pointer to data to send to device
- length number of bytes to send to the device
- statusType < 0 => do transfer using SCSIWBlind
- >= 0 => do transfer using SCSIWrite
- abs(statusType) is number of bytes to transfer in each SCSI data burst
- owner indicates who generated the CheckStatus request
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_CheckStatus(Ptr pData, long length, short statusType, OSType owner)
- {
- OSErr anErr = noErr;
- SCSIInstr tibProgram[9];
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- SpecGlobalsPtr pGlobals;
- Boolean doCmndNow = true;
-
- HLock((Handle) hGlobals);
- pGlobals = *hGlobals;
-
- // Is this a CheckStatus request that we generated?
- if (owner == kDrvrCreatorType)
- {
- // Check to see if it's a DrawBits command and that we now have the bitmap data
- if ( pGlobals->scsiCommand[0] == kSCDrawBits )
- {
- // Have we already received the parameters to the DrawBits command?
- if ( pGlobals->haveDrawBitsParams )
- {
- // Get control of the SCSI bus before issuing the command
- anErr = SCSIGet();
- require(anErr == noErr, SCSIGetFails1);
-
- // Select the target device on the SCSI bus
- anErr = SCSISelect(pGlobals->deviceNum);
- require(anErr == noErr, SCSISelectFails1);
-
- // Now send the command to the device
- SCSICmd((Ptr) pGlobals->scsiCommand, 6);
-
- // Now we generate a SCSI Manager TIB program to send the parameters to the DrawBits command
- GenTIBProgram(tibProgram, (Ptr) pGlobals->drawbitsParams, 10, 10);
-
- // Send the DrawBits parameters to the device
- anErr = SCSIWrite((Ptr) tibProgram);
- require(anErr == noErr, SCSIWriteFails1);
- }
- else // T => Client is calling us with the DrawBits parameters; save them for later use
- {
- BlockMove(pData, (Ptr) pGlobals->drawbitsParams, length);
- pGlobals->haveDrawBitsParams = true;
- doCmndNow = false;
- }
- }
- else // T => not a DrawBits command. Complete the command during this call
- {
- // Get control of the SCSI bus before issuing the command
- anErr = SCSIGet();
- require(anErr == noErr, SCSIGetFails2);
-
- // Select the target device on the SCSI bus
- anErr = SCSISelect(pGlobals->deviceNum);
- require(anErr == noErr, SCSISelectFails2);
-
- // Now send the command to the device
- SCSICmd((Ptr) pGlobals->scsiCommand, 6);
- }
-
- // Are we completing the command during this call?
- if (doCmndNow)
- {
- short scsiStatus;
- short message;
-
- // Create a SCSI Manager TIB program to perform the last piece of the SCSI data transfer
- GenTIBProgram(tibProgram, pData, length, abs(statusType));
-
- // Determine which SCSI Manager command to perform and send the data
- if (statusType >= 0)
- {
- anErr = SCSIWrite((Ptr) tibProgram);
- require(anErr == noErr, SCSIWriteFails2);
- }
- else // T => Do data transfer using a blind transfer
- {
- anErr = SCSIWBlind((Ptr) tibProgram);
- require(anErr == noErr, SCSIWBlindFails);
- }
-
- // Now force completion of the SCSI command
- anErr = SCSIComplete(&scsiStatus, &message, pGlobals->timeoutForSCSIComplete);
- require(anErr == noErr, SCSICompleteFails);
-
- // Remember the last SCSI status in the globals
- pGlobals->lastSCSIStatus = scsiStatus;
- }
- // else - We received the DrawBits parameters; can't do command now
- }
- else // T => This is not our CheckStatus request; pass it along the message chain
- {
- anErr = Forward_GXCheckStatus(pData, length, statusType, owner);
- require(anErr == noErr, Forward_GXCheckStatusFails);
- }
-
- /******* Clean-up *******/
-
- SCSICompleteFails:
- SCSIWBlindFails:
- SCSIWriteFails2:
- SCSIWriteFails1:
- SCSISelectFails2:
- SCSIGetFails2:
- SCSISelectFails1:
- SCSIGetFails1:
- Forward_GXCheckStatusFails:
- HUnlock((Handle) hGlobals);
-
- return(anErr);
- }
- /* SD_CheckStatus */
-
-
- /****************************************************************************************
-
- SD_GetDeviceStatus
-
- function:
- This routine is called by the Printing Manager to query the current status
- of the device. This driver does not use this routine to retrieve
- the status of the device. Rather, it uses the routine to retrieve the
- status value returned from last SCSI Manager SCSIComplete command and to
- retrieve data from the device.
-
- If the responseData pointer is non-nil, then the routine will attempt to
- read data from the printer. In this case, responseData points to the buffer
- to hold the data received; responseSize specifies the number of bytes to
- read; and cmdSize specifies the number of bytes to transfer in each SCSI data
- burst, and whether we should use the SCSIRead or SCSIRBlind routines to
- accomplish the data transfer. If cmdSize is positive, then we should use
- SCSIRead; otherwise we use should SCSIRBlind. The absolute value of
- cmdSize specifies the number of bytes to transfer in each SCSI data burst.
-
- If the responseData pointer is nil, then the routine returns the status
- value from the last SCSI Manager SCSIComplete command. All other
- parameters are ignored.
-
- parameters:
- cmdData not used
- cmdSize if responseData != nil then
- < 0 => do transfer using SCSIRBlind
- >= 0 => do transfer using SCSIRead
- abs(cmdSize) is number of bytes to transfer in each SCSI data burst
- responseData if responseData != nil, read data from device; otherwise ignored
- responseSize if responseData != nil, specifies the number of bytes to read from device;
- Otherwise, returns the status from the last SCSIComplete call
- termination not used
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_GetDeviceStatus(Ptr cmdData, long cmdSize, Ptr responseData, long *responseSize, Str255 termination)
- {
- #pragma unused (cmdData, termination)
-
- OSErr anErr = noErr;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- SCSIInstr tibProgram[9];
- SpecGlobalsPtr pGlobals;
-
- HLock((Handle) hGlobals);
- pGlobals = *hGlobals;
-
- // Are we to read some data from the device?
- if (responseData != nil)
- {
- short scsiStatus;
- short message;
-
- // Get control of the SCSI bus before issuing the command
- anErr = SCSIGet();
- require(anErr == noErr, SCSIGetFails);
-
- // Select the target device on the SCSI bus
- anErr = SCSISelect(pGlobals->deviceNum);
- require(anErr == noErr, SCSISelectFails);
-
- // Now send the command to the device
- SCSICmd((Ptr) pGlobals->scsiCommand, 6);
-
- // Create a SCSI Manager TIB program to perform the SCSI data transfer
- GenTIBProgram(tibProgram, responseData, *responseSize, abs(cmdSize));
-
- // Determine which SCSI Manager command to perform and read the data
- if (cmdSize >= 0)
- {
- anErr = SCSIRead((Ptr) tibProgram);
- require(anErr == noErr, SCSIReadFails);
- }
- else // T => Do data transfer using a blind transfer
- {
- anErr = SCSIRBlind((Ptr) tibProgram);
- require(anErr == noErr, SCSIRBlindFails);
- }
-
- // Now force completion of the SCSI command
- anErr = SCSIComplete(&scsiStatus, &message, pGlobals->timeoutForSCSIComplete);
- require(anErr == noErr, SCSICompleteFails);
-
- // Remember the last SCSI status in the globals
- pGlobals->lastSCSIStatus = scsiStatus;
- }
- else // T => Return the last SCSI status in the responseSize parameter
- *responseSize = (*hGlobals)->lastSCSIStatus;
-
-
- /******* Clean-up *******/
-
- SCSICompleteFails:
- SCSIRBlindFails:
- SCSIReadFails:
- SCSISelectFails:
- SCSIGetFails:
- HUnlock((Handle) hGlobals);
-
- return(anErr);
- }
- /* SD_GetDeviceStatus */
-
-
- /****************************************************************************************
-
- SD_CreateImageFile
-
- function:
- This routine is called by the Printing Manager when a new image file is to
- be created. This driver overrides this message for debugging purposes only.
- If the SCImageFileDebugFlag is defined, we forward the message with a
- new set of imageFileOptions, namely "makeImageFile + entireFile". This forces the
- Universal Driver to image the image file. This allows us to test the proper
- generation of image files. If the compile time flag is not set, then the
- this routine is a no-op; it simply forwards the message on to others in the
- message chain.
-
- parameters:
- fileSpec file spec for the image file
- imageFileOptions options to apply to the creation of the image file
- theImageFile a Printing Manager reference to the image file
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_CreateImageFile(FSSpecPtr fileSpec, long imageFileOptions, long *theImageFile)
- {
- OSErr anErr = noErr;
-
- #ifdef SCImageFileDebugFlag
- anErr = Forward_GXCreateImageFile(fileSpec, makeImageFile + entireFile, theImageFile);
- #else
- anErr = Forward_GXCreateImageFile(fileSpec, imageFileOptions, theImageFile);
- #endif
-
- check(anErr == noErr);
- return(anErr);
- }
- /* SD_CreateImageFile */
-
-
- /****************************************************************************************
-
- SD_FetchTaggedData
-
- function:
- This routine is called by the Printing Manager when a a resource is fetched
- from some resource file. This driver overrides this message to determine
- when someone is fetching the rasterPrefsType resource. If this resource
- is being fetched, and the job we're processing is not best quality, then
- we disable the halftoning feature in the resource. This should make the
- printing of just graphics a little bit faster.
-
- parameters:
- rsrcType type of the resource being retrieved
- rsrcID resource ID of the resource being retrieved
- theRsrc handle to the resource retrieved
- owner indicates who is issuing the request; only look at owners == 'drvr'
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
- {
- OSErr anErr;
-
- // First fetch the actual resource
- anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
- require(anErr == noErr, FetchTaggedData);
-
- if ( (owner == 'drvr') && // T => Fetching a driver resource
- (rsrcType == gxRasterPrefsType) && // T => type is 'rdip'
- (rsrcID == gxRasterPrefsID) && // T => ID is 0
- ( !JobIsBestQuality() ) // T => Doing rough output
- )
- {
- ( (gxRasterPrefsPtr) **theRsrc)->planeSetup[0].planeOptions = gxDontSetHalftone;
- }
-
-
- /******* Clean-up *******/
-
- FetchTaggedData:
- return(anErr);
- }
- /* SD_FetchTaggedData */
-
-
- /****************************************************************************************
-
- SD_RasterDataIn
-
- function:
- This routine is called by the Printing Manager when it has completed rendering
- a single portion of a raster page. It calls this routine to send the bitmap
- to the device. The data for the SC does not require any special packaging
- other than that the rectangle to draw in must be converted to a QuickDraw
- rectangle and it's left edge must be zero based (this is what the SC engine
- expects, otherwise it returns an error 5). We update the status display
- and send the data to the device.
-
- parameters:
- hOffscreen handle to the structure which references the offscreen bitmap of data
- bandRect rectangle in which to place the data on the page
- dirtyRects dirty area within that rectangle
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_RasterDataIn (gxOffscreenHdl hOffscreen, gxRectangle *bandRect, gxRectangle *dirtyRect)
- {
-
- OSErr anErr;
- Rect rDirty;
- char lockState;
-
- /*
- // Handy dandy banding debugging code
- dprintf(notrace, "bandTop %d bandLeft %d bandBottom %d bandRight %d\n",
- bandRect->top >> 16,
- bandRect->left >> 16,
- bandRect->bottom >> 16,
- bandRect->right >> 16);
- dprintf(notrace, "dirtyTop %d dirtyLeft %d dirtyBottom %d dirtyRight %d\n",
- dirtyRect->top >> 16,
- dirtyRect->left >> 16,
- dirtyRect->bottom >> 16,
- dirtyRect->right >> 16);
- */
-
- // Create the boundary rectangle in which to "draw" the bitmap on the printer
-
- SetRect(&rDirty, F2S(bandRect->left),
- F2S(dirtyRect->top),
- F2S(bandRect->right),
- F2S(dirtyRect->bottom) );
-
- // Make sure this rectangle's left edge is zero based (required by SC)
-
- rDirty.right -= rDirty.left;
- rDirty.left = 0;
-
- // Give the app. a chance to run
-
- anErr = GXJobIdle();
- require(anErr == noErr, JobIdle);
-
- // Update the status display to indicate that we're sending data to the printer
-
- anErr = GXReportStatus(kTransmissionStatID, kSendingPartOfPageStatIdx);
- require(anErr == noErr, ReportStatus);
-
- // Make sure the offscreen bitmap is locked down before we draw
-
- lockState = HGetState((Handle) hOffscreen);
- HLock((Handle) hOffscreen);
- {
- gxBitmap *pBitmap;
- Ptr image;
-
- pBitmap = &(*hOffscreen)->thePlanes[0].theBits;
- image = pBitmap->image;
- image += pBitmap->rowBytes * (rDirty.top - F2S(bandRect->top));
- anErr = LaserSC_DrawBits(image, &rDirty, pBitmap->rowBytes, srcCopy);
- }
- HSetState((Handle) hOffscreen, lockState);
-
- require(anErr == noErr, LaserSC_DrawBits);
-
- // Update the status display to indicate that we're preparing the next chunk of data
-
- anErr = GXReportStatus(kTransmissionStatID, kPreparingPartOfPageStatIdx);
- require(anErr == noErr, ReportStatus2);
-
-
- /******* Cleanup *******/
-
- ReportStatus2:
- LaserSC_DrawBits:
- ReportStatus:
- JobIdle:
- return(anErr);
- }
- /* SD_RasterDataIn */
-
- /****************************************************************************************
-
- SD_DoesPaperFit
-
- function:
- This routine is called by the Printing Manager when the user selects the input
- trays dialog from the printing menu. The driver checks the page dimensions to
- see if it is physically possible to store the paper in the printer.
-
- parameters:
- paper papertype to check
- fits (returned) true if dimensions fit, false otherwise
-
- returns:
- noErr
-
- ****************************************************************************************/
- OSErr SD_DoesPaperFit (gxTrayIndex tray, gxPaperType paper, Boolean *fits)
- {
- gxRectangle paperSize;
- fixed paperWidth, paperHeight, tempFixed;
-
- GXGetPaperTypeDimensions(paper, nil, &paperSize);
- paperWidth = paperSize.right - paperSize.left;
- paperHeight = paperSize.bottom - paperSize.top;
-
- *fits = false;
-
- // for simplicity, make sure paperHeight >= paperWidth
-
- if ( paperWidth > paperHeight ) {
- tempFixed = paperWidth;
- paperWidth = paperHeight;
- paperHeight = tempFixed;
- }
-
- // the SC supports 5 paper sizes
- // widths range from kEnvelopeWidth to kUSLetterWidth
- // heights range from kEnvelopeHeight to kUSLegalHeight
-
- if (( paperWidth >= kEnvelopeWidth ) && ( paperWidth <= kUSLetterWidth ))
- if (( paperHeight >= kEnvelopeHeight ) && (paperHeight <= kUSLegalHeight )) {
-
- if ( paperWidth == kUSLetterWidth ) {
- if (( paperHeight == kUSLetterHeight ) || ( paperHeight == kUSLegalHeight ))
- *fits = true;
- }
- else if (( paperWidth == kA4LetterWidth ) && ( paperHeight == kA4LetterHeight ))
- *fits = true;
- else if (( paperWidth == kB5LetterWidth ) && ( paperHeight == kB5LetterHeight ))
- *fits = true;
- else if (( paperWidth == kEnvelopeWidth ) && ( paperHeight == kEnvelopeHeight ))
- *fits = true;
- }
-
- return( noErr );
- }
-